<!--
 * @Description: 表格，支持滚动/插槽
 * @Author BPF
 * @create 2021/12/5 14:26
 -->
<!--default-->
<script>
export default { name: 'g-table' }
</script>

<!--setup-->
<script setup>
import TableTemplate from './components/table-template'
import { Base, MathUtils, Type, Dom } from '@bianpengfei/utils'
import { computed, onMounted, onUnmounted, reactive, watch, getCurrentInstance, nextTick } from 'vue'
const { Decimal } = MathUtils

let _throttleOnBodyScroll = null // 内容区域滚动时
let _debounceOnChangeBodySize = null // 当body尺寸发生变化
let _clientWidth = 0 // 内容去宽度
let _scrollView = null
let _bodyDOM = null
let _bodyFixLeftDOM = null
let _bodyFixRightDOM = null
const { proxy } = getCurrentInstance()

const props = defineProps({
  autoConvertNumber: {
    type: Boolean, // 是否默认开启转化数据
    default: true
  },
  data: {
    type: Array,
    default: () => []
  },

  forceFormat: {
    // 是否强行格式化 成w单位
    type: Boolean,
    default: false
  },

  columns: {
    type: Array,
    default: () => [
      {
        label: '序号', // title名
        type: 'index', // 有两种类型  一个是index  一个是link
        width: '1rem', // 宽度
        fixed: 'left' // 固定左侧
      },
      {
        label: '科室名称',
        type: 'link',
        prop: 'KS_NAME', // 属性值
        width: '2rem',
        fixed: 'right'
      },
      { label: '门诊', prop: 'V_YLFWXW_MJZ_MZRC_KS', width: '2rem', forceFormat: true },
      { label: '初诊', prop: 'V_YLFWXW_MJZ_MZCZRC_KS', width: '2rem' },
      { label: '复诊', prop: 'V_YLFWXW_MJZ_MZFZRC_KS', width: '2rem' },
      { label: '复诊率', prop: 'fzl', width: '1rem' }
    ]
  },

  collapseLength: {
    // 折叠长度
    type: Number,
    default: 5
  },

  enableCollapseScroll: {
    // 是否开启，每次折叠后，回滚到原来位置  默认开启
    type: Boolean,
    default: true
  }
})
defineEmits({})
const state = reactive({
  isCollapsed: true,
  isFixedLeft: false,
  isFixedRight: false,
  clientWidth: '100%',
  sortColumn: {
    id: '',
    prop: '',
    sort: 0 // 1 up  -1 down
  }
}) // data

const tableColumnsCp = computed(() => {
  const { columns } = props
  const widthArr = columns.map(v => v.width).filter(v => !!v)
  const len = columns.length - widthArr.length
  const list = columns.map(v => {
    v._ID = Math.random().toString(16).slice(2)
    v.fixedSortIdx = v.fixed == 'left' ? 1 : v.fixed == 'right' ? -1 : 0
    v.style = {
      // fix ios 有的不支持 calc(100% - 0.8rem)问题
      width: v.width || (widthArr.length ? `calc((${_clientWidth} - ${widthArr.join('-')}) / ${len}) ` : 'auto')
      // width: `calc((${this.clientWidth} - ${widthArr.join('+')}) / ${len}) `
    }
    return v
  })
  list.sort((a, b) => (b.fixedSortIdx > a.fixedSortIdx ? 1 : -1))
  return list
})

// 表格数据
const tableDataCp = computed(() => {
  const { autoConvertNumber, collapseLength, columns, forceFormat } = props
  let data = props.data.slice()
  const __ORIGIN_ = '__ORIGIN_'
  const columnsObj = columns.reduce((pre, cur) => {
    cur.prop && (pre[cur.prop] = cur)
    return pre
  }, {})
  data = data.map(v => {
    const result = { __IS_ESCAPE: false } // __IS_ESCAPE 是否转义过
    Object.entries(v).forEach(([key, value]) => {
      if (Type.isNumber(value) && !key.startsWith('__')) {
        // 如果每一项中column中forceFormat为true或者设置全局forceFormat为true，每一项中column优先级更高
        const tempForceFormat = Object.prototype.hasOwnProperty.call(columnsObj[key] || {}, 'forceFormat')
          ? !!columnsObj[key]?.forceFormat
          : forceFormat
        if (tempForceFormat || (autoConvertNumber && value > 10 ** 4)) {
          result[key] = `${new Decimal(+value).div(10 ** 4).toFixed(2)}w`
          result[`${__ORIGIN_}${key}`] = value
          result.__IS_ESCAPE = true
        }
      }
    })
    return { ...v, ...result }
  })
  const prop = state.sortColumn.prop
  // console.log('prop', prop)
  if (prop) {
    if (state.sortColumn.sort == 1) {
      data.sort((a, b) => {
        let aVal = a.__IS_ESCAPE ? +a[`${__ORIGIN_}${prop}`] : +a[prop]
        let bVal = b.__IS_ESCAPE ? +b[`${__ORIGIN_}${prop}`] : +b[prop]
        aVal ||= 0
        bVal ||= 0
        return aVal < bVal ? 1 : -1
      })
    } else {
      data.sort((a, b) => {
        let aVal = a.__IS_ESCAPE ? +a[`${__ORIGIN_}${prop}`] : +a[prop]
        let bVal = b.__IS_ESCAPE ? +b[`${__ORIGIN_}${prop}`] : +b[prop]
        aVal ||= 0
        bVal ||= 0
        return bVal < aVal ? 1 : -1
      })
    }
  }
  return state.isCollapsed ? data.slice(0, collapseLength) : data.slice()
})

// 左侧悬浮固定头部数组
const tableColumnsFixLeftCp = computed(() => {
  return tableColumnsCp.value.filter(v => v.fixed == 'left') || []
})

// 右侧悬浮固定头部数组
const tableColumnsFixRightCp = computed(() => {
  return tableColumnsCp.value.filter(v => v.fixed == 'right')
})

/**
 * 监听
 */
watch([tableDataCp, tableColumnsCp], onChangeData)

onMounted(() => {
  _bodyDOM = proxy.$refs.body
  _bodyFixLeftDOM = proxy.$refs.bodyFixLeft
  _bodyFixRightDOM = proxy.$refs.bodyFixRight
  if (proxy.$refs.container) _clientWidth = proxy.$refs.container.clientWidth + 'px'
  // console.log('打印 mounted', proxy.$refs.container, _bodyDOM)
  _throttleOnBodyScroll = Base.throttle(onBodyScroll, 20)
  _debounceOnChangeBodySize = Base.debounce(onChangeBodySize, 200)
  _bodyDOM.addEventListener('scroll', _throttleOnBodyScroll, false)
  window.addEventListener('resize', _debounceOnChangeBodySize, false)
  _scrollView = Dom.getParentIsScrollView(proxy.$refs.container) || document.body
  onBodyScroll()
  onChangeBodySize()
})

onUnmounted(() => {
  _bodyDOM && _bodyDOM.removeEventListener('scroll', _throttleOnBodyScroll)
  window.removeEventListener('resize', _debounceOnChangeBodySize, false)
})

function onBodyScroll() {
  // console.log('滚动了')
  if (tableColumnsFixLeftCp.value.length) {
    state.isFixedLeft = _bodyDOM.scrollLeft > 0
  }
  if (tableColumnsFixRightCp.value.length) {
    state.isFixedRight = _bodyDOM.scrollWidth - _bodyDOM.scrollLeft - proxy.$refs.container.clientWidth > 10
  }
}

function onChangeBodySize() {
  onChangeData()
}

function onChangeData() {
  requestAnimationFrame(() => {
    const fixLeftTrList = _bodyFixLeftDOM?.querySelectorAll('table tr') || []
    const fixRightTrList = _bodyFixRightDOM?.querySelectorAll('table tr') || []
    const trList = _bodyDOM.querySelectorAll('table tr')
    ;[fixLeftTrList, fixRightTrList].forEach(list => {
      list.forEach((el, idx) => {
        if (el) {
          const tempEl = trList[idx]
          if (tempEl) {
            el.style.height = `${tempEl.clientHeight}px`
            el.style.width = `${tempEl.clientWidth}px`
            // el.style.transition = `0.3s all`
          }
        }
      })
    })
  })
}

/**
 * 折叠、展开
 */
function onCollapse() {
  const { enableCollapseScroll } = props
  state.isCollapsed = !state.isCollapsed
  if (enableCollapseScroll && _scrollView) {
    nextTick(() => {
      const scrollTop = Dom.getOffsetTop(proxy.$refs.container, _scrollView, 0)
      Dom.scrollToY(_scrollView, _scrollView.scrollTop, scrollTop)
    })
  }
}

/**
 * 点击排序
 * @param val
 */
function onSort(val) {
  const conf = {
    1: -1,
    0: -1,
    '-1': 1
  }
  state.sortColumn = {
    id: val._ID,
    sort: conf[String(state.sortColumn.sort)] || 0,
    prop: val.prop,
    ...val
  }
}
</script>

<!--render-->
<template>
  <div class="table-container" ref="container">
    <!--  主体内容  -->
    <div class="table__body" ref="body">
      <table-template :data="tableDataCp" :columns="tableColumnsCp" @onSort="onSort" :sortColumn="state.sortColumn">
        <template v-slot="scoped">
          <template v-for="thItem in tableColumnsCp">
            <slot v-if="thItem.slot" :name="thItem.slot" v-bind="scoped"></slot>
          </template>
        </template>
      </table-template>
    </div>

    <!--  左侧固定  -->
    <div
      :class="['table__body--fix', state.isFixedLeft && 'table__body--fix-shadow', 'table__body--fix-left']"
      v-if="tableColumnsFixLeftCp.length"
      ref="bodyFixLeft"
    >
      <table-template
        :data="tableDataCp"
        :columns="tableColumnsFixLeftCp"
        :sortColumn="state.sortColumn"
        :showEmpty="false"
      >
        <template v-slot="scoped">
          <template v-for="(thItem, thIndex) in tableColumnsFixLeftCp" :key="thIndex">
            <slot v-if="thItem.slot" :name="thItem.slot" v-bind="scoped"></slot>
          </template>
        </template>
      </table-template>
    </div>

    <!--  右侧固定  -->
    <div
      :class="['table__body--fix', state.isFixedRight && 'table__body--fix-shadow', 'table__body--fix-right']"
      v-if="tableColumnsFixRightCp.length"
      ref="bodyFixRight"
    >
      <table-template
        :data="tableDataCp"
        :columns="tableColumnsFixRightCp"
        :sortColumn="state.sortColumn"
        :showEmpty="false"
      >
        <template v-slot="scoped">
          <template v-for="thItem in tableColumnsFixRightCp">
            <slot v-if="thItem.slot" :name="thItem.slot" v-bind="scoped"></slot>
          </template>
        </template>
      </table-template>
    </div>

    <!-- 收缩、展开-->
    <div v-if="data.length > props.collapseLength" class="table-collapse" @click="onCollapse">
      <template v-if="state.isCollapsed"> <van-icon name="arrow-down" /> &nbsp;展开更多 </template>
      <template v-else> <van-icon name="arrow-up" />&nbsp;收缩 </template>
    </div>
  </div>
</template>

<!--style-->
<style scoped lang="less">
.table-container {
  color: @primary-color;
  min-height: 0.8rem;
  font-size: 0.28rem;
  width: 100%;
  background-color: #fff;
  border-radius: 0.1rem;
  position: relative;
  //overflow: hidden;
  .table-collapse {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 0.88rem;
    font-size: 0.28rem;
  }
  .font-blue {
    color: @primary-color;
  }
  .text-underline {
    text-decoration: underline;
  }
  .table__header {
    overflow-x: auto;
    table {
      width: 100%;
    }
  }
  .table__body {
    overflow-x: auto;
    :deep(table) {
      width: 100%;
      border: 1px solid #ddd !important;
    }
  }
  .table__body--fix {
    position: absolute;
    top: 0.02rem;
    z-index: 10;
    overflow-x: hidden;
    overflow-y: hidden;
    width: fit-content;
    &.table__body--fix-shadow {
      box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.2);
    }
    &.table__body--fix-right {
      right: 0;
    }
    &.table__body--fix-left {
      left: 0;
    }
    :deep(.table-empty) {
      opacity: 0;
    }
  }
  ::-webkit-scrollbar {
    display: none;
  }
}
</style>
